<template>
  <div
    class="h-full w-full relative workflow-canvas-root"
    @dragover.prevent
    @drop="onDrop"
  >
    <NodePanelDrawer
      :visible="nodePanelVisible"
      @visibility-change="handleNodePanelVisibilityChange"
      @node-select="handleNodeSelect"
    />

    <!-- 浮动节点快速搜索（无分类，出现在拖拽释放位置） -->
    <NodeQuickSearch
      :visible="quickSearch.visible"
      :x="quickSearch.x"
      :y="quickSearch.y"
      @node-select="handleNodeSelect"
      @close="quickSearch.visible = false"
    />

    <!-- 边分支选择器：用于将某条边切换到指定分支（source-idx） -->
    <EdgeBranchPicker
      :visible="edgeBranchPicker.visible"
      :x="edgeBranchPicker.x"
      :y="edgeBranchPicker.y"
      :branches="edgeBranchPicker.branches"
      @pick="handlePickBranch"
      @close="edgeBranchPicker.visible = false"
    />
    <!-- 变量管理按钮 -->
    <div class="toolbar-left" v-show="!nodePanelVisible">
      <a-button
        @click="toggleVariables"
        type="primary"
        status="success"
        size="small"
      >
        <template #icon>
          <icon-file />
        </template>
        变量
      </a-button>
    </div>

    <!-- 工具栏（居中） -->
    <div class="toolbar-center">
      <a-button
        @click="resetNodes"
        type="primary"
        status="warning"
        size="small"
      >
        <template #icon>
          <icon-delete />
        </template>
        重置节点
      </a-button>
      <a-upload
        accept=".json"
        :show-file-list="false"
        :auto-upload="false"
        :limit="1"
        v-model:file-list="importFileList"
        @change="loadWorkflow"
      >
        <template #upload-button>
          <a-button type="primary" status="normal" size="small">
            <template #icon>
              <icon-folder />
            </template>
            导入流程</a-button
          >
        </template>
      </a-upload>
      <a-button
        @click="downloadWorkflow"
        type="primary"
        status="normal"
        size="small"
      >
        <template #icon>
          <icon-save />
        </template>
        下载
      </a-button>
      <a-button
        @click="saveToServer"
        type="primary"
        status="success"
        size="small"
      >
        <template #icon>
          <icon-save />
        </template>
        保存
      </a-button>
    </div>

    <!-- Vue Flow 画布 -->
    <VueFlow
      v-model:nodes="nodes"
      v-model:edges="edges"
      :node-types="nodeTypes"
      :connection-mode="ConnectionMode.Loose"
      :connection-line-style="{ stroke: '#10b981', strokeWidth: 2 }"
      :is-valid-connection="isValidConnection"
      @connect="onConnect"
      @connect-start="onConnectStart"
      @connect-end="onConnectEnd"
      @nodes-change="onNodesChange"
      @edges-change="onEdgesChange"
      @node-click="onNodeClick"
      @pane-click="onPaneClick"
      @edge-double-click="onEdgeDoubleClick"
      @edge-click="onEdgeClick"
      @edge-context-menu="onEdgeContextMenu"
      @viewport-change="onViewportChange"
      @node-drag-start="onNodeDragStart"
      @node-drag-stop="onNodeDragStop"
      @pane-context-menu="onPaneContextMenu"
      class="h-full w-full workflow-flow"
      :default-viewport="{ x: 0, y: 0, zoom: 1 }"
      :min-zoom="0.2"
      :max-zoom="4"
      :fit-view="false"
      :fit-view-on-init="false"
      :pan-on-drag="true"
      :pan-on-scroll="false"
      :zoom-on-scroll="true"
      :zoom-on-double-click="false"
      :prevent-scroll="false"
      :nodes-draggable="true"
      :nodes-connectable="true"
      :elements-selectable="true"
      :auto-connect="false"
      :select-nodes-on-drag="true"
      style="position: relative; overflow: visible"
    >
      <Background pattern="dots" :gap="10" />
    </VueFlow>

    <!-- MiniMap 小地图 -->
    <!-- 暂时移除MiniMap，避免viewBox错误 -->
    <!--
    <MiniMap
      v-if="showMiniMap"
      :pannable="true"
      :zoomable="true"
      style="
        position: absolute;
        bottom: 20px;
        right: 20px;
        width: 200px;
        height: 120px;
        z-index: 1000;
        border-radius: 6px;
        overflow: hidden;
        background: var(--color-bg-2, #fff);
        border: 1px solid var(--color-border-2, #e5e7eb);
      "
    />
    -->

    <!-- 自定义控件 -->
    <div class="custom-controls">
      <button @click="zoomIn" class="control-btn">
        <span>+</span>
      </button>
      <button @click="zoomOut" class="control-btn">
        <span>-</span>
      </button>
      <button @click="fitView" class="control-btn">
        <span>⊞</span>
      </button>
    </div>

    <!-- 变量管理面板 -->
    <VariablePanel v-if="showVariables" @close="showVariables = false" />

    <!-- 节点属性面板 -->
    <component
      v-if="selectedNode"
      :is="getConfigPanel(selectedNode.type)"
      :node="selectedNode"
      :nodes="nodes"
      :edges="edges"
      :variables="variables"
      @update="updateNodeProperties"
      @close="selectedNode = null"
    />

    <!-- 重置确认对话框 -->
    <a-modal
      v-model:visible="showResetConfirm"
      title="确认清空节点"
      ok-text="确认清空"
      cancel-text="取消"
      @ok="handleResetConfirm"
      @cancel="cancelReset"
      :mask-closable="false"
      :closable="false"
      :width="350"
      class="reset-confirm-modal"
      draggable
    >
      <div style="padding: 0px 0">
        <div
          style="
            color: #f53f3f;
            font-weight: bold;
            font-size: 14px;
            margin-bottom: 8px;
          "
        >
          警告
        </div>
        此操作将删除所有节点和连线，且无法恢复。确定要清空所有节点吗？
      </div>
    </a-modal>
  </div>
</template>

<script setup lang="ts">
import {
  ref,
  computed,
  onMounted,
  onUnmounted,
  markRaw,
  watch,
  nextTick,
} from "vue";
import {
  VueFlow,
  useVueFlow,
  type Node,
  type Edge,
  type Connection,
  ConnectionMode,
  type GraphNode,
} from "@vue-flow/core";
import { Background } from "@vue-flow/background";
import { Controls } from "@vue-flow/controls";
import { MiniMap } from "@vue-flow/minimap";
import {
  IconDelete,
  IconLink,
  IconFile,
  IconSave,
  IconFolder,
  IconRefresh,
} from "@arco-design/web-vue/es/icon";
import { Modal } from "@arco-design/web-vue";
import { Message } from "@arco-design/web-vue";
import {
  saveProcess,
  type ProcessDTO,
  type NodeCreateDTO,
} from "@/api/workflow";

import NodePanelDrawer from "./nodePanelDrawer.vue";
import NodeQuickSearch from "./nodeQuickSearch.vue";
import EdgeBranchPicker from "./edgeBranchPicker.vue";
import ConditionNode from "../nodes/conditionNode.vue";
import ControlNode from "../nodes/controlNode.vue";
import PersonNode from "../nodes/personNode.vue";
import ApprovalNode from "../nodes/approvalNode.vue";
import AutoNode from "../nodes/autoNode.vue";
import ConditionNodeConfigPanel from "../panel/conditionNodeConfigPanel.vue";
import ControlNodeConfigPanel from "../panel/controlNodeConfigPanel.vue";
import DefaultNodeConfigPanel from "../panel/defaultNodeConfigPanel.vue";
import VariablePanel from "./variablePanel.vue";
import { useWorkflowVariables } from "@/components/workflow/useWorkflowVariables";
// 数据类型定义
export interface DataType {
  id: string;
  name: string;
  color: string;
}

// 从条件节点的 sourceHandle 推断边标签
function getEdgeLabelForLogic(
  sourceNode: any,
  sourceHandleId: string | null | undefined
): string | undefined {
  try {
    const h = String(sourceHandleId || "source");
    const m = h.match(/^source\-(.+)$/);
    if (
      m &&
      sourceNode &&
      sourceNode.type === "condition" &&
      Array.isArray(sourceNode.data?.branches)
    ) {
      const bid = String(m[1]);
      const found = sourceNode.data.branches.find(
        (b: any) => String(b.id || "") === bid
      );
      return found?.name;
    }
  } catch (e) {}
  return undefined;
}

// 选择一个节点的默认源句柄：
// - 条件节点(logic)优先第一个分支句柄 `source-<branch.id>`
// - 其他节点统一返回 'source'
function getDefaultSourceHandleId(node: any): string {
  try {
    if (
      node &&
      node.type === "condition" &&
      Array.isArray(node.data?.branches) &&
      node.data.branches.length > 0
    ) {
      const first = node.data.branches[0];
      const bid = String(first?.id ?? "0");
      return `source-${bid}`;
    }
  } catch (e) {}
  return "source";
}

// 根据基础名称在现有节点中生成自增且唯一的名称，例如："人工节点" -> "人工节点1"、"人工节点2"
function generateAutoLabel(base: string): string {
  const cleanBase = String(base || "节点").trim() || "节点";
  const labels = (nodes.value || []).map((n: any) => String(n?.data?.label || ""));
  // 收集已使用的数字后缀
  const used = new Set<number>();
  for (const lbl of labels) {
    const m = lbl.match(new RegExp(`^${cleanBase}(\\d+)$`));
    if (m) {
      used.add(Number(m[1]));
    }
  }
  // 从1开始寻找未被占用的编号
  let i = 1;
  while (used.has(i)) i++;
  return `${cleanBase}${i}`;
}

// 基于 DOM 的命中检测：用屏幕坐标识别落点所在的 Vue Flow 节点并判定左右半
function getDomTargetAtClientPoint(
  clientX: number,
  clientY: number
): { id: string; targetHandle: "target" | "target-right" } | null {
  const el = document.elementFromPoint(clientX, clientY) as HTMLElement | null;
  if (!el) return null;
  // 向上寻找带有 data-id 的节点容器（Vue Flow 节点外层一般有 data-id 和类名 vue-flow__node）
  let nodeEl: HTMLElement | null = el;
  while (nodeEl && !nodeEl.dataset?.id) {
    nodeEl = nodeEl.parentElement as HTMLElement | null;
  }
  const id = nodeEl?.dataset?.id;
  if (!id || !(nodeEl instanceof HTMLElement)) return null;
  const rect = nodeEl.getBoundingClientRect();
  const centerX = rect.left + rect.width / 2;
  const targetHandle = clientX <= centerX ? "target" : "target-right";
  return { id, targetHandle };
}

function onEdgeContextMenu(edgeMouseEvent: any) {
  try {
    const ev: MouseEvent | undefined = edgeMouseEvent?.event || edgeMouseEvent;
    const edge =
      edgeMouseEvent?.edge ||
      edgeMouseEvent?.data?.edge ||
      edgeMouseEvent?.payload ||
      null;
    if (!edge) return;
    const srcNode = findNode(edge.source);
    // 仅当源节点为条件节点时才允许切换分支
    if (!srcNode || (srcNode as any).type !== "condition") return;
    const branches = (srcNode as any)?.data?.branches || [];
    if (!ev) return;
    edgeBranchPicker.value = {
      visible: true,
      x: ev.clientX,
      y: ev.clientY,
      edgeId: edge.id,
      sourceNodeId: edge.source,
      targetNodeId: edge.target,
      branches,
    };
    ev.preventDefault();
  } catch (e) {
    console.warn("edge contextmenu open picker failed", e);
  }
}

export interface NodePort {
  id: string;
  label: string;
  type: DataType;
}

export interface WorkflowVariable {
  id: string;
  name: string;
  type: string;
  defaultValue: any;
  description: string;
}

export interface WorkflowNode extends Node {
  data: {
    label: string;
    description?: string;
    inputs?: NodePort[];
    outputs?: NodePort[];
    variables?: string[];
    color?: string;
    branches?: Array<{ id?: string; name: string; condition?: string }>;
  };
}

// 数据类型定义
const dataTypes: DataType[] = [
  { id: "string", name: "文本", color: "#10b981" },
  { id: "number", name: "数值", color: "#3b82f6" },
  { id: "boolean", name: "布尔", color: "#8b5cf6" },
  { id: "object", name: "对象", color: "#f59e0b" },
];

// Vue Flow 实例
const {
  findNode,
  addNodes,
  addEdges,
  removeNodes,
  removeEdges,
  getSelectedNodes,
  getSelectedEdges,
  setViewport,
  toObject,
  setEdges,
  setNodes,
  zoomIn: vueFlowZoomIn,
  zoomOut: vueFlowZoomOut,
  fitView: vueFlowFitView,
  project,
  getNodes,
} = useVueFlow();

// 全局变量仓库（流程变量、出参变量、系统变量）
const {
  processVariables: procVars,
  outputVariables: outVars,
  systemVariables: sysVars,
} = useWorkflowVariables();

// 绑定导入上传的文件列表，用于在导入后清空，避免累计导致读取到第一次的文件
const importFileList = ref<any[]>([]);

// 连接拖拽时记录鼠标位置（用于判定目标节点左/右半）
let lastMouse = { clientX: 0, clientY: 0 } as {
  clientX: number;
  clientY: number;
};
function onMouseMoveDuringConnect(e: MouseEvent) {
  lastMouse = { clientX: e.clientX, clientY: e.clientY };
}

// —— 新增：将指定节点的 outputs 同步至全局出参变量 ——
function syncOutputsForNode(node: any) {
  try {
    const rawId = String(node?.id || "");
    const data = (node as any)?.data || {};
    const nodeKey = String(data?.nodeKey || rawId);
    const nodeLabel = String(data?.label || "");
    const outputs = Array.isArray(data?.outputs) ? data.outputs : [];
    if (!rawId || outputs.length === 0) return;

    // 先移除该节点旧的出参与变量映射
    const prefix = `node-${rawId}-`;
    outVars.value = (outVars.value || []).filter(
      (v) => !String(v?.id || "").startsWith(prefix)
    );

    for (const it of outputs) {
      const key = String((it as any)?.key || "").trim();
      const name = String((it as any)?.name || "").trim();
      if (!key || !name) continue;
      const id = `${prefix}${key}`;
      const display = `\${${nodeLabel},${key}}`;
      const value = `\${${nodeKey},${key}}`;
      outVars.value.push({ id, name, value, display });
    }
  } catch (e) {
    try {
      console.warn("syncOutputsForNode failed", e);
    } catch {}
  }
}

// 命中检测：根据画布坐标，判断光标是否位于某个节点卡片内
function getNodeAtPoint(pt: { x: number; y: number }) {
  // 从上到下遍历，优先后渲染节点（可根据需要调整）
  for (let i = nodes.value.length - 1; i >= 0; i--) {
    const n: any = nodes.value[i] as any;
    const dims: any = n.dimensions || n.computed?.dimensions;
    const posAbs: any = n.positionAbsolute || n.computed?.position;
    if (!dims || !posAbs || dims.width == null || dims.height == null) continue;
    const x1 = Number(posAbs.x);
    const y1 = Number(posAbs.y);
    const x2 = x1 + Number(dims.width);
    const y2 = y1 + Number(dims.height);
    if (pt.x >= x1 && pt.x <= x2 && pt.y >= y1 && pt.y <= y2) {
      return n as WorkflowNode;
    }
  }
  return null;
}

// 连接开始：记录源节点与句柄
const onConnectStart = (params: any) => {
  console.log("连接开始", params);
  // params 可能包含 nodeId/handleId/handleType，做兼容处理
  const sourceId = params?.nodeId || params?.node?.id || params?.source || "";
  const sourceHandle =
    params?.handleId || params?.handle || params?.sourceHandle || null;
  const handleType = params?.handleType || params?.type || null;
  if (sourceId) {
    if (handleType === "target") {
      // 从目标点开始拖拽
      pendingConnection.value = {
        startedAt: "target",
        targetId: sourceId,
        targetHandle: sourceHandle,
      };
    } else {
      // 默认从源点开始拖拽
      pendingConnection.value = { startedAt: "source", sourceId, sourceHandle };
    }
  } else {
    pendingConnection.value = null;
  }
  // 重置成功标记
  didConnectSuccessfully.value = false;
  // 开始监听鼠标移动以记录位置
  try {
    window.addEventListener("mousemove", onMouseMoveDuringConnect);
  } catch (e) {}
  // 调试：确认起始句柄
  try {
    console.log("[connect-start] handle:", sourceHandle);
  } catch (e) {}
};

// 连接结束：如果没有成功连接到目标，则弹出节点面板，选择后再创建并连线
const onConnectEnd = (event: MouseEvent) => {
  // 成功连接则直接清理并返回
  if (didConnectSuccessfully.value) {
    pendingConnection.value = null;
    didConnectSuccessfully.value = false;
    try {
      window.removeEventListener("mousemove", onMouseMoveDuringConnect);
    } catch (e) {}
    return;
  }
  if (!pendingConnection.value) return;

  // 优先尝试：DOM 命中检测（无需精确到句柄）
  const domTarget = getDomTargetAtClientPoint(event.clientX, event.clientY);
  if (domTarget) {
    let connection: any | null = null;
    if (pendingConnection.value.startedAt === "source") {
      if (domTarget.id !== pendingConnection.value.sourceId) {
        const srcHandle = String(
          pendingConnection.value.sourceHandle || "source"
        );
        const srcSide: "left" | "right" = srcHandle.includes("-left")
          ? "left"
          : "right";
        const forcedTargetHandle =
          srcSide === "right" ? "target" : "target-right";
        connection = {
          source: pendingConnection.value.sourceId,
          sourceHandle: pendingConnection.value.sourceHandle || "source",
          target: domTarget.id,
          targetHandle: forcedTargetHandle,
        };
      }
    } else if (pendingConnection.value.startedAt === "target") {
      if (domTarget.id !== pendingConnection.value.targetId) {
        // 从目标开始：将落点节点作为 source，起始节点作为 target
        const srcNode = findNode(domTarget.id);
        const sourceHandleId = getDefaultSourceHandleId(srcNode as any);
        const srcSide: "left" | "right" = sourceHandleId.includes("-left")
          ? "left"
          : "right";
        const forcedTargetHandle =
          srcSide === "right" ? "target" : "target-right";
        connection = {
          source: domTarget.id,
          sourceHandle: sourceHandleId,
          target: pendingConnection.value.targetId,
          targetHandle: forcedTargetHandle,
        };
      }
    }
    if (connection && isValidConnection(connection)) {
      onConnect(connection as Connection);
      pendingConnection.value = null;
      try {
        window.removeEventListener("mousemove", onMouseMoveDuringConnect);
      } catch (e) {}
      return;
    }
  }

  // 其次尝试：基于数据的矩形命中
  const pt = project({ x: event.clientX, y: event.clientY });
  const targetNode = getNodeAtPoint(pt);
  if (targetNode) {
    let connection: any | null = null;
    if (pendingConnection.value.startedAt === "source") {
      if (targetNode.id !== pendingConnection.value.sourceId) {
        const srcHandle = String(
          pendingConnection.value.sourceHandle || "source"
        );
        const srcSide: "left" | "right" = srcHandle.includes("-left")
          ? "left"
          : "right";
        const forcedTargetHandle =
          srcSide === "right" ? "target" : "target-right";
        connection = {
          source: pendingConnection.value.sourceId,
          sourceHandle: pendingConnection.value.sourceHandle || "source",
          target: targetNode.id,
          targetHandle: forcedTargetHandle,
        };
      }
    } else if (pendingConnection.value.startedAt === "target") {
      if (targetNode.id !== pendingConnection.value.targetId) {
        // 从目标开始：将落点节点作为 source，起始节点作为 target
        const srcNode = findNode(targetNode.id);
        const sourceHandleId = getDefaultSourceHandleId(srcNode as any);
        const srcSide: "left" | "right" = sourceHandleId.includes("-left")
          ? "left"
          : "right";
        const forcedTargetHandle =
          srcSide === "right" ? "target" : "target-right";
        connection = {
          source: targetNode.id,
          sourceHandle: sourceHandleId,
          target: pendingConnection.value.targetId,
          targetHandle: forcedTargetHandle,
        };
      }
    }
    if (connection && isValidConnection(connection)) {
      onConnect(connection as Connection);
      pendingConnection.value = null;
      try {
        window.removeEventListener("mousemove", onMouseMoveDuringConnect);
      } catch (e) {}
      return;
    }
  }

  // 若未命中任何节点，再回退到打开快速搜索
  paneContextMenuPosition.value = { x: event.clientX, y: event.clientY };
  quickSearch.value = { visible: true, x: event.clientX, y: event.clientY };
  // 不清理 pendingConnection，供 handleNodeSelect 使用
  try {
    window.removeEventListener("mousemove", onMouseMoveDuringConnect);
  } catch (e) {}
};

// 响应式数据
const nodes = ref<WorkflowNode[]>([]);

// 规范节点类型：若出现未注册到 nodeTypes 的类型，统一归一到 'default'
// 同时为 logic 节点的 branches 保持稳定的 id（按索引回填上一次的 id）
const prevBranchIds = new Map<string, string[]>(); // nodeId -> branch ids by index
watch(
  nodes,
  (val) => {
    if (!Array.isArray(val)) return;
    let changed = false;
    const normalized = val.map((n) => {
      const known = Object.prototype.hasOwnProperty.call(
        nodeTypes,
        n.type || ""
      );
      let nn: any = n;
      if (!known) {
        changed = true;
        nn = { ...n, type: "default" } as any;
      }
      // 纠偏：如果历史数据中被归一到 default，但具备条件节点的特征（存在 branches），则改回 condition
      if (
        (nn as any).type === "default" &&
        Array.isArray((nn as any).data?.branches)
      ) {
        changed = true;
        nn = { ...nn, type: "condition" } as any;
      }
      // 不再按类型回填分类：完全依赖节点自身 data.category（由抽屉选择或拖拽注入）
      // 为 logic 节点的每个分支补充稳定的 id
      if (
        (nn as any).type === "condition" &&
        Array.isArray((nn as any).data?.branches)
      ) {
        const prevIds = prevBranchIds.get(nn.id) || [];
        const branches = (nn as any).data.branches.map(
          (b: any, idx: number) => {
            const ensuredId = b?.id || prevIds[idx] || generateShortUUID();
            return { ...b, id: ensuredId };
          }
        );
        if (
          branches.some(
            (b: any, idx: number) => (nn as any).data.branches[idx]?.id !== b.id
          )
        ) {
          changed = true;
          nn = { ...nn, data: { ...(nn as any).data, branches } };
        }
        // 更新缓存
        const ids = branches.map((b: any) => b.id);
        prevBranchIds.set(nn.id, ids);
      }
      return nn;
    });
    if (changed) setNodes(normalized as any);
  },
  { deep: true }
);

const edges = ref<Edge[]>([]);
const variables = ref<WorkflowVariable[]>([]);
const showVariables = ref(false);
const selectedNode = ref<WorkflowNode | null>(null);
const showMiniMap = ref(false);
const nodePanelVisible = ref(false);
const quickSearch = ref({ visible: false, x: 0, y: 0 });

const edgeBranchPicker = ref<{
  visible: boolean;
  x: number;
  y: number;
  edgeId: string | null;
  sourceNodeId: string | null;
  targetNodeId?: string | null;
  branches: Array<{ name: string; condition?: string }>;
}>({
  visible: false,
  x: 0,
  y: 0,
  edgeId: null,
  sourceNodeId: null,
  targetNodeId: null,
  branches: [],
});
const showResetConfirm = ref(false);
const paneContextMenuPosition = ref({ x: 0, y: 0 });

// 连接拖拽临时状态
// 支持从 source 或 target 开始拖拽
const pendingConnection = ref<
  | {
      startedAt: "source";
      sourceId: string;
      sourceHandle: string | null;
    }
  | {
      startedAt: "target";
      targetId: string;
      targetHandle: string | null;
    }
  | null
>(null);
const didConnectSuccessfully = ref(false);

// 切换变量面板显示
const toggleVariables = () => {
  showVariables.value = !showVariables.value;
};

// 延迟显示MiniMap
const toggleMiniMap = () => {
  // 立即隐藏MiniMap
  showMiniMap.value = false;

  if (!selectedNode.value && nodes.value.length > 0) {
    // 延迟显示MiniMap，确保视图数据已经准备好
    setTimeout(() => {
      // 再次检查条件，确保在延迟期间状态没有改变
      if (!selectedNode.value && nodes.value.length > 0) {
        showMiniMap.value = true;
      }
    }, 500); // 增加延迟时间到500ms
  }
};

// 监听selectedNode变化
watch(selectedNode, toggleMiniMap);
watch(nodes, toggleMiniMap, { deep: true });

// 视口状态管理
const viewportState = ref({
  zoom: 1,
  x: 0,
  y: 0,
});

// 拖拽状态管理
const dragState = ref({
  isDragging: false,
  savedViewport: { zoom: 1, x: 0, y: 0 },
});

// 节点拖拽开始
const onNodeDragStart = () => {
  dragState.value.isDragging = true;
  dragState.value.savedViewport = { ...viewportState.value };
};

// 节点拖拽结束
const onNodeDragStop = () => {
  dragState.value.isDragging = false;
  // 不恢复视口状态，让节点可以正常拖拽
  // setViewport(dragState.value.savedViewport);
  // viewportState.value = { ...dragState.value.savedViewport };
};

// 生成8位UUID的工具函数
const generateShortUUID = (): string => {
  // 使用 36 进制并截取，生成较短且分布更均匀的随机 ID
  return Math.random().toString(36).substring(2, 10);
};

// 节点类型映射：不同类型映射到对应节点组件（控制节点单独样式）
const nodeTypes: any = {
  condition: markRaw(ConditionNode),
  form: markRaw(PersonNode),
  auto: markRaw(AutoNode),
  approval: markRaw(ApprovalNode),
  custom: markRaw(ConditionNode),
  control: markRaw(ControlNode),
  // default: markRaw(ConditionNode),
};

// 移除节点ID计数器，改用UUID
// let nodeIdCounter = 2;

// 连接验证
const isValidConnection = (connection: Connection): boolean => {
  const sourceNode = findNode(connection.source!);
  const targetNode = findNode(connection.target!);

  if (!sourceNode || !targetNode) return false;

  // 句柄规则：来源必须是 source / source-idx；并且强制“交叉侧”连接
  // - 源右侧(source*) => 只能连 目标左侧(target)
  // - 源左侧(source-left*) => 只能连 目标右侧(target-right) [预留]
  const srcHandle = String(connection.sourceHandle || "");
  const isSourceHandleValid = /^source(\-.+)?$/.test(srcHandle);
  if (!isSourceHandleValid) return false;
  const sourceSide: "left" | "right" = srcHandle.includes("-left")
    ? "left"
    : "right";
  const requiredTargetHandle =
    sourceSide === "right" ? "target" : "target-right";
  if (connection.targetHandle !== requiredTargetHandle) return false;

  // 连接数量限制：
  // - 仅条件节点(logic)右侧可多连；其他源节点右侧最多1条
  // - 仅控制节点(control)左侧可多连；其他目标节点左侧最多1条
  const sType = (sourceNode as any).type;
  const tType = (targetNode as any).type;

  const outgoingCount = edges.value.filter(
    (e) =>
      e.source === connection.source &&
      String(e.sourceHandle || "source") === String(connection.sourceHandle)
  ).length;
  const incomingCount = edges.value.filter(
    (e) =>
      e.target === connection.target &&
      String(e.targetHandle || "target") === String(connection.targetHandle)
  ).length;

  // 禁止同一对节点形成相反方向的连接（已存在 target->source 时，禁止 source->target）
  const hasReverse = edges.value.some(
    (e) => e.source === connection.target && e.target === connection.source
  );
  if (hasReverse) return false;

  // 源侧限制
  if (sType !== "condition" && outgoingCount >= 1) return false;

  // 目标侧限制
  if (tType !== "control" && incomingCount >= 1) return false;

  return true;
};

// 处理连接
const onConnect = (connection: Connection) => {
  // 标记此次连接成功，用于在 connect-end 中避免重复创建节点
  didConnectSuccessfully.value = true;
  try {
    console.log("[connect] sourceHandle:", connection.sourceHandle);
  } catch (e) {}
  // 最终强制交叉侧规则：源右->目标左，源左->目标右
  try {
    const srcHandle = String(connection.sourceHandle || "source");
    const srcSide: "left" | "right" = srcHandle.includes("-left")
      ? "left"
      : "right";
    const forcedTargetHandle = srcSide === "right" ? "target" : "target-right";
    (connection as any).targetHandle = forcedTargetHandle;
  } catch (e) {}
  // 仅在条件节点(condition)上，根据 sourceHandle 推断分支名，设置边标签
  let edgeLabel: string | undefined;
  const sourceHandle = String(connection.sourceHandle || "source");
  const match = sourceHandle.match(/^source\-(.+)$/);
  const source = findNode(connection.source!);
  if (
    match &&
    source &&
    source.type === "condition" &&
    Array.isArray((source as any).data?.branches)
  ) {
    const bid = String(match[1]);
    const found = (source as any).data.branches.find(
      (b: any) => String(b.id || "") === bid
    );
    edgeLabel = found?.name;
  }
  addEdges([
    {
      id: `${connection.source}-${String(connection.sourceHandle || "source")}-${connection.target}-${generateShortUUID()}`,
      source: connection.source!,
      target: connection.target!,
      sourceHandle: connection.sourceHandle,
      targetHandle: connection.targetHandle || "target",
      animated: true,
      style: { stroke: "#10b981", strokeWidth: 2 },
      label: edgeLabel,
    },
  ]);
  try {
    console.log(
      "[onConnect] edges after add:",
      edges.value.map((e) => e.id)
    );
  } catch (e) {}

  // 连接后自动选择目标节点
  const targetNode = findNode(connection.target!);
  if (targetNode) {
    selectedNode.value = targetNode;
  }
  try {
    window.removeEventListener("mousemove", onMouseMoveDuringConnect);
  } catch (e) {}
};

// 节点变化处理
const onNodesChange = (changes: any[]) => {
  // console.log('节点变化处理')
  // 处理所有节点变化，包括位置变化
  changes.forEach((change) => {
    if (change.type === "add") {
      // 新节点添加处理
    }
    if (change.type === "remove") {
      // 节点删除处理
    }
    if (change.type === "position") {
      // 节点位置变化处理
    }
  });
};

// 边变化处理
const onEdgesChange = (changes: any[]) => {
  // console.log('边变化处理')
  // 可以在这里处理边的变化
};

// 更新节点属性
const updateNodeProperties = (nodeId: string, properties: any) => {
  const node = findNode(nodeId);
  if (!node) return;

  // 对名称进行必填、唯一性校验
  if (Object.prototype.hasOwnProperty.call(properties, "label")) {
    const next = String((properties as any)?.label ?? "").trim();
    if (!next) {
      Message.error("请填写节点名称");
      return;
    }
    const duplicated = (nodes.value || []).some(
      (n: any) => n.id !== nodeId && String(n?.data?.label || "").trim() === next
    );
    if (duplicated) {
      Message.error("节点名称需全局唯一");
      return;
    }
    // 使用去空格后的名称
    (properties as any).label = next;
  }

  Object.assign(node.data, properties);
};

// 下载工作流
const downloadWorkflow = () => {
  // 检查是否有节点
  if (nodes.value.length === 0) {
    alert("请先添加节点再保存流程！");
    return;
  }

  // 将节点对象的id字段映射为nodeKey字段
  const nodesWithNodeKey = nodes.value.map((node) => {
    const { id, ...rest } = node;
    return {
      ...rest,
      nodeKey: id,
    };
  });

  const workflow = {
    nodes: nodesWithNodeKey,
    // 瘦身边数据，移除冗余字段（sourceNode、targetNode、data、events）
    edges: edges.value.map((e: any) => {
      const { sourceNode, targetNode, data, events, ...rest } = e || {};
      return rest;
    }),
    variables: variables.value,
  };

  const blob = new Blob([JSON.stringify(workflow, null, 2)], {
    type: "application/json",
  });
  const url = URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.href = url;
  a.download = "workflow.json";
  a.click();
  URL.revokeObjectURL(url);
};

// function mapNodeTypeToBackend(
//   nodeType: string | undefined
// ): "form" | "approval" | "task" | "auto" | "control" | "condition" {
//   return nodeType;
// }

// 将前端节点映射为 NodeCreateDTO
function mapNodeToNodeCreateDTO(n: any): NodeCreateDTO {
  console.log("1111111");
  console.log(JSON.stringify(n?.data?.formData));
  return {
    // 前端不再生成/传递 nodeId，nodeId 由后端生成与返回
    nodeKey: n.id,
    nodeName: n?.data?.label ?? "",
    viewId: n?.data?.formViewId,
    viewJson: JSON.stringify(n?.data?.formData),
    nodeType: n?.type,
    tip: n?.data?.description,
    // noticeTag: undefined,
    // noticeInitiator: undefined,
    // timeOut: undefined,
    // task: n?.data?.task,
    // funcDTO: undefined,
    // nodeNoticeAddDTOs: undefined,
    // childModelId: undefined,
    // childVersion: undefined,
    // rejectProcessConfEntity: undefined,
    // autoSkip: undefined,
    nodeSkip: false,
  };
}

// 将前端边映射为 NodeLineDTO 内部的 line/edge 结构
function mapEdgeToLineDTO(e: any) {
  const { sourceNode, targetNode, data, events, ...rest } = e || {};
  // NodeLineDTO.edges -> SequenceCreateDTO
  return {
    sequenceKey: rest.id,
    fromNodeId: rest.source,
    toNodeId: rest.target,
    // 条件字段可选：若有标签则标记为 yes，否则不传/或 'no'
    ...(rest.label ? { condition: "yes" } : {}),
  };
}

//组装请求json
function buildProcessDTO(): ProcessDTO {
  // 计算步数：可理解为节点数或包含连线数，这里先用节点数
  const stepNums = nodes.value.length;
  const model = {
    // ProcessCreateDTO - 必填先给出合理默认值，后续由页面输入对接
    modelId: undefined,
    modelName: "测试流程",
    processType: "normal", // plan/normal
    changeProcess: false,
    stepNums,
    version: 1,
    transact: true,

    oldVersion: undefined,
    icon: undefined,
    failToRestart: false,
  };

  const nodeDTOs = nodes.value.map((n) => mapNodeToNodeCreateDTO(n));
  const lineDTO = {
    edges: edges.value.map((e) => mapEdgeToLineDTO(e)),
  };

  // 组装三类变量到后端期望的 ProcessVariableAddDTO 结构
  const allVars = [
    ...(procVars?.value || []),
    ...(outVars?.value || []),
    ...(sysVars?.value || []),
  ].map((it: any) => ({
    displayValue: String(it?.name ?? ""),
    key: String(it?.value ?? ""),
  }));

  // 组装执行目标 NodeTargetAddDTO[]
  const cut = (s: string, n: number) => (s && s.length > n ? s.slice(0, n) : s);
  const nodeTargetAddDTOs: Array<{
    nodeKey: string;
    value: string;
    type: string;
  }> = [];
  for (const n of nodes.value as any[]) {
    const nodeKey = String(n?.id || "");
    const exec = (n as any)?.data?.executeTarget || {};
    // 目前面板仅支持用户多选，映射为 type: 'user'
    const users: string[] = Array.isArray(exec?.users) ? exec.users : [];
    for (const uid of users) {
      if (!uid) continue;
      nodeTargetAddDTOs.push({
        nodeKey: cut(nodeKey, 40),
        value: cut(String(uid), 128),
        type: cut("user", 10),
      });
    }
    // 预留：若后续扩展组织或变量来源，可在此追加
    const groups: string[] = Array.isArray(exec?.groups) ? exec.groups : [];
    for (const gid of groups) {
      if (!gid) continue;
      nodeTargetAddDTOs.push({
        nodeKey: cut(nodeKey, 40),
        value: cut(String(gid), 128),
        type: cut("user_group", 10),
      });
    }
    const vars: string[] = Array.isArray(exec?.variables) ? exec.variables : [];
    for (const vid of vars) {
      if (!vid) continue;
      nodeTargetAddDTOs.push({
        nodeKey: cut(nodeKey, 40),
        value: cut(String(vid), 128),
        type: cut("variable", 10),
      });
    }
  }

  // 组装节点出参 NodeOutputDTO[]（来源于每个节点 data.outputs）
  const nodeOutputAddDTOs: Array<{
    nodeKey: string;
    alias: string;
    expression: string;
    type: string;
    index: number;
    defaultValue: string;
  }> = [];
  for (const n of nodes.value as any[]) {
    const nodeKey = String(n?.id || "");
    const list: any[] = Array.isArray((n as any)?.data?.outputs)
      ? (n as any).data.outputs
      : [];
    const isMuted = Boolean((n as any)?.data?.muted);
    list.forEach((it: any, idx: number) => {
      console.log("222", it?.value);
      const key = String(it?.key || "").trim();
      const name = String(it?.name || "").trim();
      const tp = String(it?.type || "string").trim();
      if (!key || !name) return;
      nodeOutputAddDTOs.push({
        nodeKey,
        alias: name,
        expression: key,
        type: tp,
        index: idx,
        defaultValue: isMuted ? String(it?.value ?? "") : "",
      });
    });
  }
  return {
    model: model,
    nodes: nodeDTOs,
    nodeLineDTO: lineDTO,
    processVariableAddDTOs: allVars,
    nodeTargetAddDTOs,
    nodeOutputAddDTOs,
  };
}

// 保存到后端（发送 ProcessDTO）
async function saveToServer() {
  try {
    const payload: ProcessDTO = buildProcessDTO();
    // return;
    const result = await saveProcess(payload).catch((e: any) => {
      throw e;
    });
    Modal.success({
      title: "保存成功",
      content: `已保存到后端`,
    });
  } catch (e: any) {
    Modal.error({
      title: "保存失败",
      content: e?.message || "网络或服务异常",
    });
  }
}

// 加载工作流（Arco Upload onChange(fileList, file)）
const loadWorkflow = async (fileList: any[], fileItem?: any) => {
  // 优先使用当前变更的文件，其次使用列表最后一个
  const cur = fileItem || fileList?.[fileList.length - 1];
  const file = cur?.file || cur?.originFileObj;
  if (!file) return;

  const reader = new FileReader();
  reader.onload = async (e) => {
    try {
      const workflow = JSON.parse(e.target?.result as string);
      // 先彻底清空响应式数组
      nodes.value = [];
      edges.value = [];
      await nextTick(); // 等待视图和内部状态同步

      // 节点数据校验和补全
      const nodesWithId = (workflow.nodes || []).map(
        (node: any, idx: number) => {
          const { nodeKey, id, type, position, data, ...rest } = node;
          return {
            id: nodeKey || id || `node_${idx}`,
            type: type || "custom",
            position:
              position &&
              typeof position.x === "number" &&
              typeof position.y === "number"
                ? position
                : { x: 0, y: 0 },
            data: (() => {
              const d =
                typeof data === "object" && data !== null
                  ? data
                  : { label: "未命名节点" };
              return {
                ...d,
                nodeKey: (d as any).nodeKey ?? (nodeKey || id || `node_${idx}`),
              };
            })(),
            ...rest,
          };
        }
      );
      const nodeIdSet = new Set(nodesWithId.map((n) => n.id));
      // 边数据校验
      const edgesWithCheck = (workflow.edges || [])
        .map((edge: any, idx: number) => {
          const { id, source, target, ...rest } = edge;
          return {
            id: id || `edge_${idx}`,
            source,
            target,
            ...rest,
          };
        })
        .filter((e) => nodeIdSet.has(e.source) && nodeIdSet.has(e.target));

      // 用API添加
      if (nodesWithId.length > 0) addNodes(nodesWithId);
      if (edgesWithCheck.length > 0) addEdges(edgesWithCheck);
      variables.value = workflow.variables || [];

      // 聚合所有节点的出参到全局 outputVariables
      try {
        const aggregated: Array<{
          id: string;
          name: string;
          value: string;
          display?: string;
        }> = [];
        for (const n of nodesWithId) {
          const rawId = String(n?.id || "");
          const nodeKey = String((n as any)?.data?.nodeKey ?? rawId);
          const nodeLabel = String((n as any)?.data?.label || "");
          if (!rawId || !nodeKey) continue;
          const prefix = `node-${rawId}-`;
          const list = Array.isArray((n as any)?.data?.outputs)
            ? (n as any).data.outputs
            : [];
          for (const it of list) {
            const key = String((it as any)?.key || "").trim();
            const name = String((it as any)?.name || "").trim();
            if (!key || !name) continue;
            const id = `${prefix}${key}`;
            const value = `\${${nodeKey},${key}}`;
            const display = `\${${nodeLabel},${key}}`;
            aggregated.push({ id, name, value, display });
          }
        }
        outVars.value = aggregated;
      } catch (e) {
        console.warn("aggregate output variables on import failed", e);
      }

      // 重置视口到默认状态
      setTimeout(() => {
        setViewport({ x: 0, y: 0, zoom: 1 });
        viewportState.value = { zoom: 1, x: 0, y: 0 };
      }, 100);
      // 清空上传文件列表，避免累计导致下次仍读到旧文件
      try {
        importFileList.value = [];
      } catch (e) {}
    } catch (error) {
      alert("文件格式错误！");
    }
  };
  reader.readAsText(file);
};

function onDrop(e: DragEvent) {
  const nodeType = e.dataTransfer?.getData("nodeType");
  if (!nodeType) return;
  const nodeCategory = e.dataTransfer?.getData("nodeCategory") || undefined;
  // 计算画布坐标（考虑画布滚动和缩放）
  const bounds = (e.currentTarget as HTMLElement).getBoundingClientRect();
  // 获取VueFlow实例的transform（x, y, zoom）
  const flow = document.querySelector(".vue-flow");
  let offsetX = 0,
    offsetY = 0,
    zoom = 1;
  if (flow) {
    const transformElement = flow.querySelector(
      ".vue-flow__transformation"
    ) as HTMLElement;
    if (transformElement) {
      const transform = transformElement.style.transform;
      if (transform) {
        const match =
          /translate\((-?\d+\.?\d*)px, ?(-?\d+\.?\d*)px\) scale\((\d+\.?\d*)\)/.exec(
            transform
          );
        if (match) {
          offsetX = parseFloat(match[1]);
          offsetY = parseFloat(match[2]);
          zoom = parseFloat(match[3]);
        }
      }
    }
  }
  // 鼠标在画布中的坐标，需减去transform偏移并除以缩放
  const x = (e.clientX - bounds.left - offsetX) / zoom;
  const y = (e.clientY - bounds.top - offsetY) / zoom;
  // 节点ID使用8位UUID
  const nodeKey = generateShortUUID();
  // 节点数据模板
  let nodeData: any = {};
  if (nodeType === "approval") {
    nodeData = {
      label: "审批节点",
      description: "审批流程节点",
      category: nodeCategory,
    };
  } else if (nodeType === "custom") {
    nodeData = {
      label: "自定义节点",
      description: "自定义功能节点",
      category: nodeCategory,
    };
  } else if (nodeType === "condition") {
    nodeData = {
      label: "条件节点",
      description: "逻辑判断节点",
      branches: [
        {
          id: generateShortUUID(),
          name: "分支A",
          condition: "name=100&&age>20",
        },
        {
          id: generateShortUUID(),
          name: "分支B",
          condition: "name!=100||age<=20",
        },
      ],
      category: nodeCategory,
    };
  } else if (nodeType === "control") {
    nodeData = {
      label: "控制节点",
      description: "流程控制节点",
      category: nodeCategory,
      control: {
        mode: "all",
        selectedNodeKeys: [],
        selectedNodeLabels: [],
      },
    };
  } else if (nodeType === "form") {
    nodeData = {
      label: "人工节点",
      description: "",
      category: nodeCategory,
    };
  } else if (nodeType === "auto") {
    nodeData = {
      label: "自动化节点",
      description: "",
      category: nodeCategory,
    };
  } else {
    nodeData = {
      label: nodeType,
      description: "",
      category: nodeCategory,
    };
  }
  const newNode: WorkflowNode = {
    id: nodeKey,
    type: nodeType,
    position: { x, y },
    data: { ...nodeData, nodeKey },
  };
  addNodes([newNode]);
}

// 1. 监听节点点击事件，设置selectedNode，若已选中则关闭
function onNodeClick(nodeMouseEvent: any) {
  console.log("节点点击事件");
  const node = nodeMouseEvent.node;

  // 直接设置selectedNode，不依赖Vue Flow的选择机制
  if (selectedNode.value && selectedNode.value.id === node.id) {
    selectedNode.value = null;
  } else {
    selectedNode.value = node;
  }
}

// 2. 监听画布点击事件，隐藏抽屉
function onPaneClick() {
  // 若当前处于拖拽（节点或框选）中，则不处理点击，以免误清空选择
  if (dragState.value?.isDragging) {
    return;
  }
  console.log("画布点击事件触发");
  selectedNode.value = null;
  // 关闭右键弹出的节点快速搜索框
  // try {
  //   quickSearch.value.visible = false;
  // } catch (e) {}
}

// 4. 监听画布右键事件，打开节点列表
function onPaneContextMenu(event: MouseEvent) {
  // 阻止默认右键菜单
  event.preventDefault();

  // 记录右键点击位置
  paneContextMenuPosition.value = { x: event.clientX, y: event.clientY };
  // 打开浮动快速搜索框（无分类）
  quickSearch.value = { visible: true, x: event.clientX, y: event.clientY };
  // 确保左侧抽屉关闭
  nodePanelVisible.value = false;
}

// 单击边：打开分支选择器（仅逻辑节点）
function onEdgeClick(edgeMouseEvent: any) {
  try {
    const ev: MouseEvent | undefined = edgeMouseEvent?.event || edgeMouseEvent;
    const edge =
      edgeMouseEvent?.edge ||
      edgeMouseEvent?.data?.edge ||
      edgeMouseEvent?.payload ||
      null;
    if (!edge) return;
    const srcNode = findNode(edge.source);
    if (!srcNode || (srcNode as any).type !== "condition") return;
    const branches = (srcNode as any)?.data?.branches || [];
    if (!ev) return;
    edgeBranchPicker.value = {
      visible: true,
      x: ev.clientX,
      y: ev.clientY,
      edgeId: edge.id,
      branches,
      sourceNodeId: edge.source,
      targetNodeId: edge.target,
    } as any;
  } catch (e) {
    console.error(e);
  }
}

// 双击边：删除该连线
function onEdgeDoubleClick(edgeMouseEvent: any) {
  try {
    const edge =
      edgeMouseEvent?.edge ||
      edgeMouseEvent?.data?.edge ||
      edgeMouseEvent?.payload ||
      null;
    if (!edge) return;
    removeEdges([edge.id]);
    // 同时关闭可能已打开的分支选择器
    if (edgeBranchPicker.value.visible) edgeBranchPicker.value.visible = false;
  } catch (e) {
    console.error(e);
  }
}

function getConfigPanel(type) {
  switch (type) {
    case "condition":
      return ConditionNodeConfigPanel;
    case "control":
      return ControlNodeConfigPanel;
    // 其余类型（如 input/approval/process/custom/output/default）统一使用默认面板
    default:
      return DefaultNodeConfigPanel;
  }
}

// 自定义控件功能
function zoomIn() {
  vueFlowZoomIn();
}

function zoomOut() {
  vueFlowZoomOut();
}

function fitView() {
  vueFlowFitView();
}

// 视口变化处理
const onViewportChange = (viewport: any) => {
  // 只有在用户主动缩放或平移时才更新视口状态
  // 防止拖拽节点时意外改变视口
  const currentZoom = viewportState.value.zoom;
  const newZoom = viewport.zoom;

  // 如果缩放变化很小（可能是拖拽引起的），则忽略
  if (Math.abs(newZoom - currentZoom) < 0.01) {
    return;
  }

  viewportState.value = {
    zoom: viewport.zoom,
    x: viewport.x,
    y: viewport.y,
  };
};

// 重置视口到默认状态
const resetViewport = () => {
  setViewport({ x: 0, y: 0, zoom: 1 });
  viewportState.value = { zoom: 1, x: 0, y: 0 };
};

// 重置所有节点
const resetNodes = () => {
  showResetConfirm.value = true;
};

// 处理重置确认
const handleResetConfirm = () => {
  removeNodes(nodes.value.map((node) => node.id));
  removeEdges(edges.value.map((edge) => edge.id));
  // 移除重置节点ID计数器的代码
  // nodeIdCounter = 2; // 重置节点ID计数器
  showResetConfirm.value = false;
};

// 取消重置
const cancelReset = () => {
  showResetConfirm.value = false;
};

// 处理NodePanelDrawer的visibility-change事件
const handleNodePanelVisibilityChange = (visible: boolean) => {
  nodePanelVisible.value = visible;
};

// 处理NodePanelDrawer的node-select事件
const handleNodeSelect = (node: any) => {
  // 使用Vue Flow的project函数将屏幕坐标转换为画布坐标
  const point = project({
    x: paneContextMenuPosition.value.x,
    y: paneContextMenuPosition.value.y,
  });

  // 优先处理从连线释放触发的选择（补全未连接的目标节点）
  if (pendingConnection.value) {
    // 快照当前边，用于后续校验是否有旧边被意外移除
    const prevEdgesSnapshot = edges.value.map((e) => ({ ...e }));
    const newId = `${node.type}-${generateShortUUID()}`;
    const baseLabel = String(node.label || "节点");
    const autoLabel = generateAutoLabel(baseLabel);
    const newNode: WorkflowNode = {
      id: newId,
      type: node.type,
      position: { x: point.x, y: point.y },
      data: {
        label: autoLabel,
        category: node.category,
        nodeKey: newId,
        ...(node.type === "approval"
          ? {
              outputs: [{ name: "审批结果", key: "approval", type: "string" }],
            }
          : {}),
        ...(node.type === "condition"
          ? {
              branches: [
                { id: generateShortUUID(), name: "分支A", condition: "" },
                { id: generateShortUUID(), name: "分支B", condition: "" },
              ],
            }
          : {}),
      },
    };
    try {
      console.log(
        "[handleNodeSelect] edges before add node:",
        edges.value.map((e) => e.id)
      );
    } catch (e) {}
    addNodes([newNode]);
    // 同步新建节点出参到全局变量（确保审批默认出参立刻可见）
    syncOutputsForNode(newNode);
    try {
      console.log(
        "[handleNodeSelect] edges after add node (should be unchanged):",
        edges.value.map((e) => e.id)
      );
    } catch (e) {}

    // 依据拖拽起点（source/target）创建边
    if (pendingConnection.value.startedAt === "source") {
      const sId = pendingConnection.value.sourceId;
      const sHandle = String(pendingConnection.value.sourceHandle || "source");
      const sNode = findNode(sId) as any;
      const label = getEdgeLabelForLogic(sNode, sHandle);
      const srcSide: "left" | "right" = sHandle.includes("-left")
        ? "left"
        : "right";
      const forcedTargetHandle =
        srcSide === "right" ? "target" : "target-right";
      addEdges([
        {
          id: `${sId}-${sHandle}-${newId}-${generateShortUUID()}`,
          source: sId,
          target: newId,
          sourceHandle: sHandle,
          targetHandle: forcedTargetHandle,
          animated: true,
          style: { stroke: "#10b981", strokeWidth: 2 },
          label,
        },
      ]);
    } else if (pendingConnection.value.startedAt === "target") {
      const tId = pendingConnection.value.targetId;
      const tHandle = String(pendingConnection.value.targetHandle || "target");
      // 新增节点作为 source，选择默认 source 句柄
      const sHandle = getDefaultSourceHandleId(newNode as any);
      const sNode = newNode as any;
      const label = getEdgeLabelForLogic(sNode, sHandle);
      const srcSide: "left" | "right" = sHandle.includes("-left")
        ? "left"
        : "right";
      const forcedTargetHandle =
        srcSide === "right" ? "target" : "target-right";
      addEdges([
        {
          id: `${newId}-${sHandle}-${tId}-${generateShortUUID()}`,
          source: newId,
          target: tId,
          sourceHandle: sHandle,
          targetHandle: forcedTargetHandle,
          animated: true,
          style: { stroke: "#10b981", strokeWidth: 2 },
          label,
        },
      ]);
    }
    try {
      console.log(
        "[handleNodeSelect] edges after add edge:",
        edges.value.map((e) => e.id)
      );
    } catch (e) {}

    // 校验与修复：若发现任意旧边被意外移除，则补回（不限制 source）
    try {
      const missing = prevEdgesSnapshot.filter(
        (prev) => !edges.value.some((cur) => cur.id === prev.id)
      );
      if (missing.length > 0) {
        try {
          console.warn(
            "[handleNodeSelect] restoring missing edges:",
            missing.map((e) => e.id)
          );
        } catch (e) {}
        addEdges(missing as any);
      }
    } catch (e) {
      console.error("[handleNodeSelect] re-add missing edges failed", e);
    }

    // 选中新节点并清理连接状态
    const created = findNode(newId);
    if (created) selectedNode.value = created as any;
    pendingConnection.value = null;
    didConnectSuccessfully.value = false;
  } else {
    // 常规右键添加节点
    const newId = `${node.type}-${generateShortUUID()}`;
    const baseLabel = String(node.label || "节点");
    const autoLabel = generateAutoLabel(baseLabel);
    addNodes([
      {
        id: newId,
        type: node.type,
        position: { x: point.x, y: point.y },
        data: {
          label: autoLabel,
          category: node.category,
          nodeKey: newId,
          ...(node.type === "approval"
            ? {
                outputs: [
                  { name: "审批结果", key: "approval", type: "string" },
                ],
              }
            : {}),
          ...(node.type === "condition"
            ? {
                branches: [
                  { id: generateShortUUID(), name: "分支A", condition: "" },
                  { id: generateShortUUID(), name: "分支B", condition: "" },
                ],
              }
            : {}),
        },
      },
    ]);
    // 选取刚才 addNodes 的对象进行同步
    const created =
      findNode(newId) ||
      ({
        id: newId,
        data: {
          ...({
            label: node.label,
            category: node.category,
            nodeKey: newId,
          } as any),
        },
      } as any);
    syncOutputsForNode(created);
  }

  // 关闭面板（两个面板可能其一打开）
  nodePanelVisible.value = false;
  quickSearch.value.visible = false;
};

// 处理分支选择：仅更新边的显示名称（label）
function handlePickBranch(index: number) {
  const picker = edgeBranchPicker.value;
  if (!picker.edgeId || picker.sourceNodeId == null) {
    picker.visible = false;
    return;
  }
  const srcNode = findNode(picker.sourceNodeId);
  const branches = (srcNode as any)?.data?.branches || [];
  const br = branches[index];
  if (!br) {
    picker.visible = false;
    return;
  }
  const name = br?.name ?? "";
  // 仅更新当前这条边的 label，不改动 sourceHandle
  let edge = edges.value.find((e) => e.id === picker.edgeId);
  if (!edge && picker.sourceNodeId && (picker as any).targetNodeId) {
    edge = edges.value.find(
      (e) =>
        e.source === picker.sourceNodeId &&
        e.target === (picker as any).targetNodeId
    );
  }
  if (edge) {
    // 原地更新，避免触发全量校验
    edge.label = name;
  }
  picker.visible = false;
}

onMounted(() => {
  // 初始化视口设置
  setTimeout(() => {
    // 确保画布以正确的缩放比例初始化
    setViewport({ x: 0, y: 0, zoom: 1 });
    viewportState.value = { zoom: 1, x: 0, y: 0 };
  }, 200);

  // 添加键盘事件监听
  const handleKeyDown = (event: KeyboardEvent) => {
    if (event.key === "Delete" || event.key === "Backspace") {
      // 检查用户是否正在编辑输入框
      const activeElement = document.activeElement;
      const isEditing =
        activeElement &&
        (activeElement.tagName === "INPUT" ||
          activeElement.tagName === "TEXTAREA" ||
          (activeElement as HTMLElement).contentEditable === "true" ||
          activeElement.classList.contains("arco-input") ||
          activeElement.classList.contains("arco-textarea"));

      // 如果正在编辑输入框，则不执行删除操作
      if (isEditing) {
        return;
      }

      // 删除选中的边
      const selectedEdges = getSelectedEdges.value;
      if (selectedEdges.length > 0) {
        removeEdges(selectedEdges.map((edge) => edge.id));
        return;
      }

      // 删除选中的节点
      const selectedNodes = getSelectedNodes.value;
      if (selectedNodes.length > 0) {
        removeNodes(selectedNodes.map((node) => node.id));
      }
    }
  };

  document.addEventListener("keydown", handleKeyDown);

  // 清理事件监听
  onUnmounted(() => {
    document.removeEventListener("keydown", handleKeyDown);
  });
});
</script>

<style scoped>
.workflow-canvas-root {
  width: 100%;
  height: 100%;
  min-width: 0;
  min-height: 0;
  position: relative;
}

/* Vue Flow 基础样式 */
:deep(.vue-flow) {
  width: 100%;
  height: 100%;
}

/* Vue Flow 暗黑模式适配 */
:deep(.vue-flow__controls) {
  background: var(--color-bg-2, #fff);
  border: 1px solid var(--color-border-2, #e5e7eb);
  border-radius: 6px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

:deep(.vue-flow__controls button) {
  background: var(--color-bg-2, #fff);
  border: 1px solid var(--color-border-2, #e5e7eb);
  color: var(--color-text-1, #374151);
}

:deep(.vue-flow__controls button:hover) {
  background: var(--color-fill-2, #f3f4f6);
}

:deep(.vue-flow__minimap) {
  background: var(--color-bg-2, #fff);
  border: 1px solid var(--color-border-2, #e5e7eb);
  border-radius: 6px;
}

:deep(.vue-flow__minimap-node) {
  background: var(--color-primary-6, #3b82f6);
  border: 1px solid var(--color-primary-6, #3b82f6);
}

:deep(.vue-flow__background) {
  background: var(--color-fill-1, #f8fafc);
}

:deep(.vue-flow__background-pattern) {
  color: var(--color-border-2, #e5e7eb);
}

/* 工具栏按钮样式 */
:deep(.arco-btn) {
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

/* 工具栏容器样式 - 确保位置正确 */
.toolbar-right {
  position: absolute !important;
  top: 16px !important;
  right: 16px !important;
  z-index: 2000 !important;
  display: flex !important;
  gap: 8px !important;
  align-items: center !important;
  transition: right 0.3s ease !important;
}

.toolbar-right.with-sidebar {
  right: 500px !important;
}

.toolbar-left {
  position: absolute !important;
  top: 16px !important;
  left: 16px !important;
  z-index: 2000 !important;
  display: flex !important;
  gap: 8px !important;
  align-items: center !important;
}

/* 新增：居中工具栏 */
.toolbar-center {
  position: absolute !important;
  top: 16px !important;
  left: 50% !important;
  transform: translateX(-50%) !important;
  z-index: 2000 !important;
  display: flex !important;
  gap: 8px !important;
  align-items: center !important;
  background: var(--color-bg-2, #fff) !important;
  padding: 6px 10px !important;
  border-radius: 8px !important;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.06) !important;
}

/* 自定义控件样式 */
.custom-controls {
  position: absolute;
  bottom: 20px;
  left: 20px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  z-index: 1000;
}

.control-btn {
  width: 32px;
  height: 32px;
  background: var(--color-bg-2, #fff);
  border: 1px solid var(--color-border-2, #e5e7eb);
  border-radius: 4px;
  color: var(--color-text-1, #374151);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: all 0.2s;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.control-btn:hover {
  background: var(--color-fill-2, #f3f4f6);
}

.control-btn span {
  font-size: 16px;
  font-weight: bold;
}

/* 重置确认对话框样式 */
:deep(.reset-confirm-modal .arco-modal) {
  top: 15% !important;
  transform: none !important;
}
</style>
